package com.gitee.wsl.ext.list

import com.gitee.wsl.ext.collection.mapToMutableList
import kotlin.math.sqrt
import kotlin.random.Random

fun <T> T.toIterable(getNext: (T) -> T?) = Iterable<T> {
    object : Iterator<T> {

        var current: T? = null
        var beforeStart = true
        var next: T? = null

        override fun hasNext(): Boolean {
            if (beforeStart) return true
            if (next == null) next = getNext(current!!)
            return next != null
        }

        override fun next(): T {
            if (beforeStart) {
                current = this@toIterable
                beforeStart = false
                return current!!
            }
            current = next ?: getNext(current!!)
            next = null
            return current!!
        }
    }
}

fun Int.getDivisors(includeDividend: Boolean = true) = buildList {
    add(1)
    for (i in 2..sqrt(toFloat()).toInt()) {
        if (this@getDivisors % i == 0) {
            add(i)
            val derived = this@getDivisors / i
            if (derived != i) add(derived)
        }
    }
    if (includeDividend) add(this@getDivisors)
    sort()
}

inline fun <T> Int.timesToListOf(predicate: (Int) -> T): List<T> = (0 until this).map { predicate(it) }
inline fun <T> Int.timesToMutableListOf(predicate: (Int) -> T): MutableList<T> =
    (0 until this).mapToMutableList { predicate(it) }


fun randomIntList(size: Int, generator: Random = Random) = size.timesToListOf { generator.nextInt() }
fun randomIntList(size: Int, bound: Int, generator: Random = Random) =
    size.timesToListOf { generator.nextInt(bound) }

fun randomFloatList(size: Int, generator: Random = Random) = size.timesToListOf { generator.nextFloat() }
fun randomDoubleList(size: Int, generator: Random = Random) = size.timesToListOf { generator.nextDouble() }
fun randomBooleanList(size: Int, generator: Random = Random) = size.timesToListOf { generator.nextBoolean() }
